module entitas{
    "use strict"
    import Group = entitas.Group
    import ISignal = entitas.utils.ISignal
    import UnorderSet = entitas.utils.UnorderSet
    import GroupChanged = entitas.Group.GroupChanged;

    export abstract  class AbstractEntityIndex {
        compIndex: number;
        group: Group;
        _onEntityAdded: GroupChanged
        _onEntityRemoved: GroupChanged
        _indexes :{}
        _fields : number[]


        constructor(index, group, ... args : number[]) {
            this.compIndex = index
            this.group = group
            this._fields = args
            this._onEntityAdded = (group, entity, index, component) => {
                this.onEntityAdded(group, entity, index, component)
            };
            this._onEntityRemoved = (group, entity, index, component) => {
                this.onEntityRemoved(group, entity, index, component)

            };
        }

        _activate() {
            this.group.onEntityAdded.add(this._onEntityAdded)
            this.group.onEntityRemoved.add(this._onEntityRemoved)
        }

        _deactivate(){
            this.group.onEntityAdded.remove(this._onEntityAdded)
            this.group.onEntityRemoved.remove(this._onEntityRemoved)
        }
        onEntityAdded(group, entity, index, component) {
            for(let k in this._fields){
                this.addEntity(component[this._fields[k]], entity)
            }
        }

        onEntityRemoved(group, entity, index, component) {
            for(let k in this._fields){
                this.removeEntity(component[this._fields[k]], entity)
            }
        }

        indexEntities(){
            var entitas = this.group.getEntities()
            var index = this.compIndex
            for(let k in entitas){
                var  entity =entitas[k]
                var component = entity.getComponent(index)
                for (let i = 0; i < this._fields.length; i++) {
                    this.addEntity(component[this._fields[i]], entity)
                }
            }
        }


        abstract addEntity(key, entity)


        abstract removeEntity(key, entity)

        clear(){

        }
    }
    
    
    class EntityIndex extends AbstractEntityIndex{
        getEntities(key) : UnorderSet {
            if(this._indexes[key] == null) {
                this._indexes[key] = new UnorderSet();
            }

            return this._indexes[key]
        }
        addEntity(key, entity) {
            var t = this.getEntities(key)
            t.insert(entity.id, entity)
            entity.addRef()
        }

        removeEntity(key, entity) {
            var t = this.getEntities(key)
            t.remove(entity.id)
            entity.release()
        }
        
    }

    class PrimaryEntityIndex extends AbstractEntityIndex{
        getEntity(key){
            return this._indexes[key]
        }
        addEntity(key, entity) {
            if (this._indexes[key]){
                //error(string.format("Entity for key '%s' already exists ! Only one entity for a primary key is allowed.", key))
            }
            this._indexes[key] = entity
            entity.addRef(this)
        }

        removeEntity(key, entity) {
            this._indexes[key] = null
            entity.release(this)
        }

    }
}
